package net.chrisjrock.display
{
	import flash.display.InteractiveObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	/**
	 * ...
	 * @author Christopher J. Rock
	 */
	public class MagicScroll 
	{
		protected var _bar:InteractiveObject;
		protected var _pos0:Point = new Point();
		protected var _pos1:Point = new Point();
		protected var _dis:Number = 0;
		protected var _angle:Number = 0;
		
		protected var _updateMethod:Function;
		
		protected var _pos:Number = 0;
		protected var _mouseOffset:Point = new Point();
		protected var _scrolling:Boolean;
		
		public function MagicScroll (bar:InteractiveObject = null , pos0:Point = null , pos1:Point = null)
		{
			setBar(bar);
			setLimits(pos0 , pos1);
		}
		
		public function destroy ():void
		{
			setBar(null);
			_updateMethod = null;
		}
		
		protected function updateToPos ():void
		{
			_bar.x = (_pos1.x - _pos0.x) * _pos + _pos0.x;
			_bar.y = (_pos1.y - _pos0.y) * _pos + _pos0.y;
		}
		
		protected function barDownHandler (event:MouseEvent):void
		{
			if (!_scrolling)
			{
				_scrolling = true;
				_bar.stage.addEventListener(MouseEvent.MOUSE_UP , barUpHandler , false , 0 , true);
				_bar.addEventListener(Event.ENTER_FRAME , barFrameHandler , false , 0 , true);
				
				_mouseOffset.x = _bar.mouseX
				_mouseOffset.y = _bar.mouseY;
			}
		}
		
		protected function barUpHandler (event:MouseEvent):void
		{
			if (_scrolling)
			{
				_scrolling = false;
				if (_bar)
				{
					if (_bar.stage)
					{
						_bar.stage.removeEventListener(MouseEvent.MOUSE_UP , barUpHandler);
					}
					_bar.addEventListener(Event.ENTER_FRAME , barFrameHandler , false , 0 , true);
				}
			}
		}
		
		protected function barFrameHandler (event:Event):void
		{
			if (!_scrolling || !_bar.parent || !_bar.stage)
			{
				barUpHandler(null);
				return ;
			}
			
			setPos(nearestPointRatio(_bar.parent.mouseX - _mouseOffset.x - _pos0.x , _bar.parent.mouseY - _mouseOffset.y - _pos0.y));
		}
		
		protected function nearestPointRatio (x:Number , y:Number):Number
		{
			return Math.cos(Math.atan2(x , y) - _angle) * Math.sqrt(x * x + y * y) / _dis;
		}
		
		public function getBar ():InteractiveObject
		{
			return _bar;
		}
		
		public function setBar (bar:InteractiveObject):void
		{
			if (_bar)
			{
				_bar.removeEventListener(MouseEvent.MOUSE_DOWN , barDownHandler);
				_bar.removeEventListener(Event.ENTER_FRAME , barFrameHandler);
				if (_bar.stage)
				{
					_bar.stage.removeEventListener(MouseEvent.MOUSE_UP , barUpHandler);
				}
			}
			
			_bar = bar;
			
			if (_bar)
			{
				_bar.addEventListener(MouseEvent.MOUSE_DOWN , barDownHandler);
				_bar.removeEventListener(Event.ENTER_FRAME , barFrameHandler);
				if (_bar.stage && _scrolling)
				{
					_bar.stage.addEventListener(MouseEvent.MOUSE_UP , barUpHandler);
				}
			}
			else
			{
				barUpHandler(null);
			}
		}
		
		public function setLimits (pos0:Point = null , pos1:Point = null):void
		{
			if (pos0)
			{
				_pos0.x = pos0.x;
				_pos0.y = pos0.y;
			}
			
			if (pos1)
			{
				_pos1.x = pos1.x;
				_pos1.y = pos1.y;
			}
			
			var diffX:Number = _pos1.x - _pos0.x;
			var diffY:Number = _pos1.y - _pos0.y;
			_dis = Math.sqrt(diffX * diffX + diffY * diffY);
			_angle = Math.atan2(diffX , diffY);
			
			updateToPos();
		}
		
		public function getPos0 ():Point
		{
			return new Point(_pos0.x , _pos0.y);
		}
		
		public function getPos1 ():Point
		{
			return new Point(_pos1.x , _pos1.y);
		}
		
		public function getUpdateMethod ():Function
		{
			return _updateMethod;
		}
		
		public function setUpdateMethod (updateMethod:Function):void
		{
			_updateMethod = updateMethod;
		}
		
		public function getPos ():Number
		{
			return _pos;
		}
		
		public function setPos (value:Number):void
		{
			_pos = value < 0 ? 0 : value > 1 ? 1 : value;
			updateToPos();
			if (Boolean(_updateMethod))
			{
				_updateMethod(_pos);
			}
		}
	}
	
}